package com.ujson.chat.client.session;

import com.ujson.base.common.utils.LogUtil;
import com.ujson.chat.common.dto.UserDto;
import com.ujson.chat.common.proto.MessageProto;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * <h3>ujson-parent</h3>
 * <p>客户端会话, 关联channel和user</p>
 *
 * @author JerryLiu  a1031757312@gmail.com
 * @version 1.0
 * @date 2021-11-23 21:49
 */
@Slf4j
@Data
public class ClientSession {
    public static final AttributeKey<ClientSession> SESSION_KEY = AttributeKey.valueOf("SESSION_KEY");
    private UserDto userDto;
    private Channel channel;
    private String sessionId;

    private AtomicBoolean isLogin = new AtomicBoolean();
    public boolean isLogin() {
        return this.isLogin.get();
    }

    public ClientSession(Channel channel) {
        this.channel = channel;
        this.sessionId = String.valueOf(-1);
        channel.attr(SESSION_KEY).set(this);
    }

    public void closeSession() {
        channel.attr(SESSION_KEY).set(null);
        channel.close();
        userDto = null;
        sessionId = null;
    }

    public static ClientSession getClientSession(Channel channel) {
        return channel.attr(ClientSession.SESSION_KEY).get();
    }

    public void loginSuccess(ChannelHandlerContext ctx, String sessionId) {
        if (Objects.isNull(channel)) {
            this.channel = ctx.channel();
        }
        channel.attr(SESSION_KEY).set(this);
        this.isLogin.set(true);
    }

    public ClientSession setUserDto(UserDto userDto) {
        this.userDto = userDto;
        return this;
    }

    public void sendMsg(MessageProto.Message message) {
        if (Objects.isNull(channel) || !this.channel.isActive()) {
            LogUtil.error(log, "channel is null or not active.");
            return ;
        }
        this.channel.writeAndFlush(message);
    }

    /** 连接/登录线程通讯 ********/
    private Object loginLock = new Object();
    private AtomicBoolean loginFlag = new AtomicBoolean();

    public void waitLogin() {
        synchronized (loginLock) {
            try {
                loginFlag.getAndSet(true);
                while (loginFlag.get()) {
                    loginLock.wait();
                }
            } catch (InterruptedException e) {}
        }
    }

    public void notifyLogin() {
        synchronized (loginLock) {
            loginFlag.getAndSet(false);
            loginLock.notifyAll();
        }
    }

}
